Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-073.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 1065343 objects.
Mean distance to the closest unit in the map: 0.396.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_dia_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:1065343     Length:1065343     Min.   :  1.0   Min.   :-196.0  
 Class :character   Class :character   1st Qu.: 91.0   1st Qu.: 144.0  
 Mode  :character   Mode  :character   Median :183.0   Median : 201.0  
                                       Mean   :182.8   Mean   : 201.5  
                                       3rd Qu.:274.0   3rd Qu.: 263.0  
                                       Max.   :366.0   Max.   : 469.0  
      tmin             precip            nevada    prof_nieve       
 Min.   :-252.00   Min.   :   0.00   Min.   :0   Min.   :   0.0000  
 1st Qu.:  47.00   1st Qu.:   0.00   1st Qu.:0   1st Qu.:   0.0000  
 Median : 100.00   Median :   0.00   Median :0   Median :   0.0000  
 Mean   :  97.54   Mean   :  17.05   Mean   :0   Mean   :   0.6185  
 3rd Qu.: 153.00   3rd Qu.:   2.00   3rd Qu.:0   3rd Qu.:   0.0000  
 Max.   : 332.00   Max.   :3361.00   Max.   :0   Max.   :1240.0000  
    longitud        latitud           altitud    
 Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:39.47   1st Qu.: -4.850   1st Qu.:  47  
 Median :41.29   Median : -1.411   Median : 287  
 Mean   :40.10   Mean   : -2.391   Mean   : 486  
 3rd Qu.:42.22   3rd Qu.:  1.296   3rd Qu.: 691  
 Max.   :43.57   Max.   :  4.216   Max.   :2535  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
16136 59396 21196  2807   449 55489 74397 14048 23490  8219 66440 45385 48975 
   14    15    16    17    18    19    20    21    22    23    24    25 
 9050 14801 76071 71707 59435 52646 54269 51998 65510 43823 71748 57858 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt       tmax       tmin     precip
[1,] -0.7547141 -0.6765823 -0.7545503  0.1803078
[2,] -0.7173476  0.3612189  0.2966718 -0.2920331

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
fecha_cnt    precip      tmax      tmin 
0.9588388 0.9540618 0.9466046 0.9442287 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 91.0   1st Qu.: 145.0   1st Qu.:  47.00   1st Qu.:  0.00  
 Median :183.0   Median : 201.0   Median : 100.00   Median :  0.00  
 Mean   :182.7   Mean   : 201.7   Mean   :  97.58   Mean   : 15.02  
 3rd Qu.:274.0   3rd Qu.: 263.0   3rd Qu.: 153.00   3rd Qu.:  1.00  
 Max.   :366.0   Max.   : 469.0   Max.   : 332.00   Max.   :488.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.47   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.29   Median : -1.411  
 Mean   :0   Mean   :   0.6129   Mean   :40.10   Mean   : -2.395  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.22   3rd Qu.:  1.296  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 287.0  
 Mean   : 485.6  
 3rd Qu.: 690.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 51.0   1st Qu.: 107.0   1st Qu.:  10.00   1st Qu.:  0.00  
 Median :108.0   Median : 144.0   Median :  46.00   Median :  0.00  
 Mean   :160.1   Mean   : 138.4   Mean   :  42.02   Mean   : 27.26  
 3rd Qu.:310.0   3rd Qu.: 175.0   3rd Qu.:  76.00   3rd Qu.: 16.00  
 Max.   :366.0   Max.   : 389.0   Max.   : 264.00   Max.   :488.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.033  
 Mean   :0   Mean   :   1.224   Mean   :41.06   Mean   : -1.655  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.401  
 Max.   :0   Max.   :1240.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 513.0  
 Mean   : 658.8  
 3rd Qu.: 890.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :130.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:225.0   1st Qu.:120.0   1st Qu.:  0.000   1st Qu.:0  
 Median :209.0   Median :261.0   Median :150.0   Median :  0.000   Median :0  
 Mean   :204.9   Mean   :263.9   Mean   :152.1   Mean   :  2.989   Mean   :0  
 3rd Qu.:259.0   3rd Qu.:300.0   3rd Qu.:183.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.661   1st Qu.:  32.0  
 Median :   0.0000   Median :40.82   Median : -1.863   Median : 108.0  
 Mean   :   0.0125   Mean   :39.16   Mean   : -3.122   Mean   : 315.5  
 3rd Qu.:   0.0000   3rd Qu.:41.77   3rd Qu.:  1.099   3rd Qu.: 566.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip        nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-200.00   Min.   : 64   Min.   :0  
 1st Qu.:144.0   1st Qu.: 120.0   1st Qu.:  62.00   1st Qu.:114   1st Qu.:0  
 Median :255.0   Median : 166.0   Median : 101.00   Median :173   Median :0  
 Mean   :225.3   Mean   : 166.7   Mean   :  95.51   Mean   :191   Mean   :0  
 3rd Qu.:309.0   3rd Qu.: 217.0   3rd Qu.: 137.00   3rd Qu.:244   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 264.00   Max.   :488   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.598   1st Qu.:  71.0  
 Median :   0.000   Median :41.96   Median : -1.650   Median : 336.0  
 Mean   :   1.373   Mean   :41.20   Mean   : -2.132   Mean   : 548.5  
 3rd Qu.:   0.000   3rd Qu.:42.59   3rd Qu.:  1.418   3rd Qu.: 785.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 48.0   1st Qu.: 106.0   1st Qu.:   8.00   1st Qu.:  0.00  
 Median :100.0   Median : 143.0   Median :  43.00   Median :  0.00  
 Mean   :153.6   Mean   : 135.6   Mean   :  36.71   Mean   : 11.04  
 3rd Qu.:311.0   3rd Qu.: 172.0   3rd Qu.:  71.00   3rd Qu.:  4.00  
 Max.   :366.0   Max.   : 303.0   Max.   : 163.00   Max.   :214.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.63   Median : -1.008  
 Mean   :0   Mean   :   1.209   Mean   :41.04   Mean   : -1.608  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.384  
 Max.   :0   Max.   :1240.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 112.0  
 Median : 515.0  
 Mean   : 669.7  
 3rd Qu.: 890.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :130.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:225.0   1st Qu.:120.0   1st Qu.:  0.000   1st Qu.:0  
 Median :209.0   Median :261.0   Median :150.0   Median :  0.000   Median :0  
 Mean   :204.9   Mean   :263.9   Mean   :152.1   Mean   :  2.989   Mean   :0  
 3rd Qu.:259.0   3rd Qu.:300.0   3rd Qu.:183.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.661   1st Qu.:  32.0  
 Median :   0.0000   Median :40.82   Median : -1.863   Median : 108.0  
 Mean   :   0.0125   Mean   :39.16   Mean   : -3.122   Mean   : 315.5  
 3rd Qu.:   0.0000   3rd Qu.:41.77   3rd Qu.:  1.099   3rd Qu.: 566.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip        nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-200.00   Min.   : 64   Min.   :0  
 1st Qu.:144.0   1st Qu.: 120.0   1st Qu.:  62.00   1st Qu.:114   1st Qu.:0  
 Median :255.0   Median : 166.0   Median : 101.00   Median :173   Median :0  
 Mean   :225.3   Mean   : 166.7   Mean   :  95.51   Mean   :191   Mean   :0  
 3rd Qu.:309.0   3rd Qu.: 217.0   3rd Qu.: 137.00   3rd Qu.:244   3rd Qu.:0  
 Max.   :366.0   Max.   : 389.0   Max.   : 264.00   Max.   :488   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.598   1st Qu.:  71.0  
 Median :   0.000   Median :41.96   Median : -1.650   Median : 336.0  
 Mean   :   1.373   Mean   :41.20   Mean   : -2.132   Mean   : 548.5  
 3rd Qu.:   0.000   3rd Qu.:42.59   3rd Qu.:  1.418   3rd Qu.: 785.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip       
 Min.   :188.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:313.0   1st Qu.: 100.0   1st Qu.:   5.00   1st Qu.:  0.000  
 Median :333.0   Median : 134.0   Median :  39.00   Median :  0.000  
 Mean   :328.1   Mean   : 127.3   Mean   :  32.65   Mean   :  5.918  
 3rd Qu.:350.0   3rd Qu.: 162.0   3rd Qu.:  66.00   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 251.0   Max.   : 122.00   Max.   :214.000  
     nevada    prof_nieve           longitud        latitud        
 Min.   :0   Min.   :   0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.70   1st Qu.: -3.7994  
 Median :0   Median :   0.0000   Median :41.65   Median :  0.3664  
 Mean   :0   Mean   :   0.5408   Mean   :41.11   Mean   : -1.3250  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.37   3rd Qu.:  1.4328  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 147.0  
 Median : 567.0  
 Mean   : 726.9  
 3rd Qu.: 916.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :130.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:225.0   1st Qu.:120.0   1st Qu.:  0.000   1st Qu.:0  
 Median :209.0   Median :261.0   Median :150.0   Median :  0.000   Median :0  
 Mean   :204.9   Mean   :263.9   Mean   :152.1   Mean   :  2.989   Mean   :0  
 3rd Qu.:259.0   3rd Qu.:300.0   3rd Qu.:183.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.661   1st Qu.:  32.0  
 Median :   0.0000   Median :40.82   Median : -1.863   Median : 108.0  
 Mean   :   0.0125   Mean   :39.16   Mean   : -3.122   Mean   : 315.5  
 3rd Qu.:   0.0000   3rd Qu.:41.77   3rd Qu.:  1.099   3rd Qu.: 566.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 32.00   1st Qu.: 110.0   1st Qu.:   9.00   1st Qu.:  0.00  
 Median : 65.00   Median : 147.0   Median :  45.00   Median :  0.00  
 Mean   : 70.16   Mean   : 139.5   Mean   :  38.66   Mean   : 13.49  
 3rd Qu.:102.00   3rd Qu.: 177.0   3rd Qu.:  73.00   3rd Qu.:  8.00  
 Max.   :235.00   Max.   : 303.0   Max.   : 163.00   Max.   :213.00  
     nevada    prof_nieve         longitud        latitud       
 Min.   :0   Min.   :   0.00   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:40.66   1st Qu.: -4.049  
 Median :0   Median :   0.00   Median :41.63   Median : -1.169  
 Mean   :0   Mean   :   1.53   Mean   :41.01   Mean   : -1.743  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.38   3rd Qu.:  1.366  
 Max.   :0   Max.   :1199.00   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  98.0  
 Median : 513.0  
 Mean   : 642.3  
 3rd Qu.: 890.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin          precip          nevada 
 Min.   :  4.0   Min.   :-54   Min.   :-110   Min.   : 64.0   Min.   :0  
 1st Qu.:213.0   1st Qu.:138   1st Qu.:  77   1st Qu.: 98.0   1st Qu.:0  
 Median :283.0   Median :187   Median : 114   Median :127.0   Median :0  
 Mean   :263.2   Mean   :185   Mean   : 109   Mean   :136.4   Mean   :0  
 3rd Qu.:319.0   3rd Qu.:231   3rd Qu.: 145   3rd Qu.:169.0   3rd Qu.:0  
 Max.   :366.0   Max.   :389   Max.   : 264   Max.   :268.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.71   1st Qu.: -5.616   1st Qu.:  69.0  
 Median :  0.0000   Median :41.84   Median : -1.885   Median : 333.0  
 Mean   :  0.3298   Mean   :41.17   Mean   : -2.274   Mean   : 495.5  
 3rd Qu.:  0.0000   3rd Qu.:42.57   3rd Qu.:  1.363   3rd Qu.: 691.0  
 Max.   :500.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip       
 Min.   :188.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:313.0   1st Qu.: 100.0   1st Qu.:   5.00   1st Qu.:  0.000  
 Median :333.0   Median : 134.0   Median :  39.00   Median :  0.000  
 Mean   :328.1   Mean   : 127.3   Mean   :  32.65   Mean   :  5.918  
 3rd Qu.:350.0   3rd Qu.: 162.0   3rd Qu.:  66.00   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 251.0   Max.   : 122.00   Max.   :214.000  
     nevada    prof_nieve           longitud        latitud        
 Min.   :0   Min.   :   0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.70   1st Qu.: -3.7994  
 Median :0   Median :   0.0000   Median :41.65   Median :  0.3664  
 Mean   :0   Mean   :   0.5408   Mean   :41.11   Mean   : -1.3250  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.37   3rd Qu.:  1.4328  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 147.0  
 Median : 567.0  
 Mean   : 726.9  
 3rd Qu.: 916.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :130.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:157.0   1st Qu.:225.0   1st Qu.:120.0   1st Qu.:  0.000   1st Qu.:0  
 Median :209.0   Median :261.0   Median :150.0   Median :  0.000   Median :0  
 Mean   :204.9   Mean   :263.9   Mean   :152.1   Mean   :  2.989   Mean   :0  
 3rd Qu.:259.0   3rd Qu.:300.0   3rd Qu.:183.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332.0   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.661   1st Qu.:  32.0  
 Median :   0.0000   Median :40.82   Median : -1.863   Median : 108.0  
 Mean   :   0.0125   Mean   :39.16   Mean   : -3.122   Mean   : 315.5  
 3rd Qu.:   0.0000   3rd Qu.:41.77   3rd Qu.:  1.099   3rd Qu.: 566.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin             precip      
 Min.   :  1.00   Min.   : -5.0   Min.   :-125.00   Min.   :  0.00  
 1st Qu.: 33.00   1st Qu.:116.0   1st Qu.:  15.00   1st Qu.:  0.00  
 Median : 66.00   Median :150.0   Median :  48.00   Median :  0.00  
 Mean   : 71.12   Mean   :146.3   Mean   :  43.95   Mean   : 13.08  
 3rd Qu.:103.00   3rd Qu.:179.0   3rd Qu.:  75.00   3rd Qu.:  7.00  
 Max.   :235.00   Max.   :303.0   Max.   : 163.00   Max.   :188.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.47   1st Qu.: -4.127  
 Median :0   Median :   0.000   Median :41.60   Median : -1.293  
 Mean   :0   Mean   :   0.771   Mean   :40.96   Mean   : -1.829  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  1.366  
 Max.   :0   Max.   :1090.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  90.0  
 Median : 446.0  
 Mean   : 583.5  
 3rd Qu.: 823.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-124.0   Min.   :-200.00   Min.   :150.0   Min.   :0  
 1st Qu.: 64.0   1st Qu.:  95.0   1st Qu.:  36.00   1st Qu.:227.0   1st Qu.:0  
 Median :127.0   Median : 136.0   Median :  78.00   Median :275.0   Median :0  
 Mean   :159.2   Mean   : 134.7   Mean   :  71.89   Mean   :286.3   Mean   :0  
 3rd Qu.:277.0   3rd Qu.: 178.0   3rd Qu.: 114.00   3rd Qu.:338.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 363.0   Max.   : 254.00   Max.   :488.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.84   1st Qu.: -5.3456   1st Qu.:  72.0  
 Median :   0.000   Median :42.08   Median :  0.3056   Median : 349.0  
 Mean   :   3.197   Mean   :41.25   Mean   : -1.8819   Mean   : 641.4  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.5242   3rd Qu.: 873.0  
 Max.   :1001.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax              tmin             precip      
 Min.   :  1.00   Min.   :-196.00   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.00   1st Qu.: -20.00   1st Qu.: -90.00   1st Qu.:  0.00  
 Median : 43.00   Median :   4.00   Median : -66.00   Median :  1.00  
 Mean   : 50.06   Mean   :  -1.23   Mean   : -71.79   Mean   : 22.06  
 3rd Qu.: 70.00   3rd Qu.:  23.00   3rd Qu.: -47.00   3rd Qu.: 30.00  
 Max.   :171.00   Max.   : 121.00   Max.   :   0.00   Max.   :213.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.00   1st Qu.:  0.72920  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  17.36   Mean   :41.98   Mean   :  0.05779  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.52420  
 Max.   :0   Max.   :1199.00   Max.   :43.36   Max.   :  3.16580  
    altitud    
 Min.   :   4  
 1st Qu.:1130  
 Median :2228  
 Mean   :1870  
 3rd Qu.:2400  
 Max.   :2535  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin          precip          nevada 
 Min.   :  4.0   Min.   :-54   Min.   :-110   Min.   : 64.0   Min.   :0  
 1st Qu.:213.0   1st Qu.:138   1st Qu.:  77   1st Qu.: 98.0   1st Qu.:0  
 Median :283.0   Median :187   Median : 114   Median :127.0   Median :0  
 Mean   :263.2   Mean   :185   Mean   : 109   Mean   :136.4   Mean   :0  
 3rd Qu.:319.0   3rd Qu.:231   3rd Qu.: 145   3rd Qu.:169.0   3rd Qu.:0  
 Max.   :366.0   Max.   :389   Max.   : 264   Max.   :268.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.71   1st Qu.: -5.616   1st Qu.:  69.0  
 Median :  0.0000   Median :41.84   Median : -1.885   Median : 333.0  
 Mean   :  0.3298   Mean   :41.17   Mean   : -2.274   Mean   : 495.5  
 3rd Qu.:  0.0000   3rd Qu.:42.57   3rd Qu.:  1.363   3rd Qu.: 691.0  
 Max.   :500.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip       
 Min.   :188.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:313.0   1st Qu.: 100.0   1st Qu.:   5.00   1st Qu.:  0.000  
 Median :333.0   Median : 134.0   Median :  39.00   Median :  0.000  
 Mean   :328.1   Mean   : 127.3   Mean   :  32.65   Mean   :  5.918  
 3rd Qu.:350.0   3rd Qu.: 162.0   3rd Qu.:  66.00   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 251.0   Max.   : 122.00   Max.   :214.000  
     nevada    prof_nieve           longitud        latitud        
 Min.   :0   Min.   :   0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.70   1st Qu.: -3.7994  
 Median :0   Median :   0.0000   Median :41.65   Median :  0.3664  
 Mean   :0   Mean   :   0.5408   Mean   :41.11   Mean   : -1.3250  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.37   3rd Qu.:  1.4328  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 147.0  
 Median : 567.0  
 Mean   : 726.9  
 3rd Qu.: 916.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   :452.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:102.0   1st Qu.:  50.50   1st Qu.:517.0   1st Qu.:0  
 Median :251.0   Median :144.0   Median :  95.00   Median :578.0   Median :0  
 Mean   :206.2   Mean   :142.6   Mean   :  86.28   Mean   :604.9   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:190.5   3rd Qu.: 131.00   3rd Qu.:673.0   3rd Qu.:0  
 Max.   :366.0   Max.   :369.0   Max.   : 241.00   Max.   :880.0   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:40.87   1st Qu.: -3.8075   1st Qu.:  52.0  
 Median :  0.00   Median :41.84   Median :  0.8342   Median : 258.0  
 Mean   :  2.44   Mean   :41.04   Mean   : -1.0514   Mean   : 608.5  
 3rd Qu.:  0.00   3rd Qu.:42.44   3rd Qu.:  1.9490   3rd Qu.: 852.0  
 Max.   :820.00   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   :  6.0   Min.   :-35.0   Min.   :-92.00   Min.   : 881   Min.   :0  
 1st Qu.: 97.0   1st Qu.: 92.0   1st Qu.: 50.00   1st Qu.: 954   1st Qu.:0  
 Median :282.0   Median :144.0   Median :103.00   Median :1059   Median :0  
 Mean   :219.7   Mean   :141.1   Mean   : 92.15   Mean   :1158   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:192.0   3rd Qu.:138.00   3rd Qu.:1276   3rd Qu.:0  
 Max.   :362.0   Max.   :298.0   Max.   :221.00   Max.   :3361   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.:  0.0714   1st Qu.:  44.0  
 Median :  0.000   Median :41.38   Median :  0.8564   Median : 251.0  
 Mean   :  2.534   Mean   :40.38   Mean   : -0.6453   Mean   : 625.8  
 3rd Qu.:  0.000   3rd Qu.:42.19   3rd Qu.:  2.1239   3rd Qu.:1002.0  
 Max.   :559.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin         precip            nevada 
 Min.   : 39.0   Min.   :130.0   Min.   :-16   Min.   :  0.000   Min.   :0  
 1st Qu.:205.0   1st Qu.:242.0   1st Qu.:129   1st Qu.:  0.000   1st Qu.:0  
 Median :240.0   Median :282.0   Median :163   Median :  0.000   Median :0  
 Mean   :241.1   Mean   :278.6   Mean   :161   Mean   :  2.821   Mean   :0  
 3rd Qu.:276.0   3rd Qu.:315.0   3rd Qu.:195   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   :332   Max.   :128.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:38.00   1st Qu.: -5.498   1st Qu.:  34.0  
 Median :   0.0000   Median :40.87   Median : -1.650   Median : 150.0  
 Mean   :   0.0075   Mean   :39.46   Mean   : -2.714   Mean   : 336.7  
 3rd Qu.:   0.0000   3rd Qu.:41.77   3rd Qu.:  1.168   3rd Qu.: 609.0  
 Max.   :1039.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin             precip      
 Min.   :  1.00   Min.   : -5.0   Min.   :-125.00   Min.   :  0.00  
 1st Qu.: 33.00   1st Qu.:116.0   1st Qu.:  15.00   1st Qu.:  0.00  
 Median : 66.00   Median :150.0   Median :  48.00   Median :  0.00  
 Mean   : 71.12   Mean   :146.3   Mean   :  43.95   Mean   : 13.08  
 3rd Qu.:103.00   3rd Qu.:179.0   3rd Qu.:  75.00   3rd Qu.:  7.00  
 Max.   :235.00   Max.   :303.0   Max.   : 163.00   Max.   :188.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.47   1st Qu.: -4.127  
 Median :0   Median :   0.000   Median :41.60   Median : -1.293  
 Mean   :0   Mean   :   0.771   Mean   :40.96   Mean   : -1.829  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  1.366  
 Max.   :0   Max.   :1090.000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  90.0  
 Median : 446.0  
 Mean   : 583.5  
 3rd Qu.: 823.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin          precip          nevada 
 Min.   :  2.0   Min.   :-66.0   Min.   :-141   Min.   :231.0   Min.   :0  
 1st Qu.:184.0   1st Qu.:134.0   1st Qu.:  77   1st Qu.:281.0   1st Qu.:0  
 Median :281.0   Median :173.0   Median : 110   Median :328.0   Median :0  
 Mean   :247.6   Mean   :173.9   Mean   : 106   Mean   :336.3   Mean   :0  
 3rd Qu.:312.0   3rd Qu.:214.0   3rd Qu.: 140   3rd Qu.:386.0   3rd Qu.:0  
 Max.   :366.0   Max.   :363.0   Max.   : 254   Max.   :488.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.78   1st Qu.: -5.4981   1st Qu.:  52.0  
 Median :  0.0000   Median :41.88   Median :  0.3181   Median : 251.0  
 Mean   :  0.5504   Mean   :41.05   Mean   : -1.8828   Mean   : 479.4  
 3rd Qu.:  0.0000   3rd Qu.:42.45   3rd Qu.:  1.7781   3rd Qu.: 661.5  
 Max.   :500.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax           tmin             precip        nevada 
 Min.   :  1.00   Min.   :-124   Min.   :-200.00   Min.   :150   Min.   :0  
 1st Qu.: 36.00   1st Qu.:  64   1st Qu.:   5.00   1st Qu.:197   1st Qu.:0  
 Median : 74.00   Median : 110   Median :  50.00   Median :230   Median :0  
 Mean   : 78.84   Mean   :  99   Mean   :  40.89   Mean   :241   Mean   :0  
 3rd Qu.:111.00   3rd Qu.: 141   3rd Qu.:  82.00   3rd Qu.:273   3rd Qu.:0  
 Max.   :362.00   Max.   : 251   Max.   : 161.00   Max.   :463   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :   0.0   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.0   1st Qu.:41.06   1st Qu.: -4.7667   1st Qu.: 108.0  
 Median :   0.0   Median :42.22   Median :  0.3056   Median : 445.0  
 Mean   :   5.6   Mean   :41.43   Mean   : -1.8810   Mean   : 788.4  
 3rd Qu.:   0.0   3rd Qu.:42.65   3rd Qu.:  1.4181   3rd Qu.:1082.0  
 Max.   :1001.0   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax              tmin             precip      
 Min.   :  1.00   Min.   :-196.00   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.00   1st Qu.: -20.00   1st Qu.: -90.00   1st Qu.:  0.00  
 Median : 43.00   Median :   4.00   Median : -66.00   Median :  1.00  
 Mean   : 50.06   Mean   :  -1.23   Mean   : -71.79   Mean   : 22.06  
 3rd Qu.: 70.00   3rd Qu.:  23.00   3rd Qu.: -47.00   3rd Qu.: 30.00  
 Max.   :171.00   Max.   : 121.00   Max.   :   0.00   Max.   :213.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.00   1st Qu.:  0.72920  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  17.36   Mean   :41.98   Mean   :  0.05779  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.52420  
 Max.   :0   Max.   :1199.00   Max.   :43.36   Max.   :  3.16580  
    altitud    
 Min.   :   4  
 1st Qu.:1130  
 Median :2228  
 Mean   :1870  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax          tmin           precip            nevada 
 Min.   :  1.0   Min.   :132   Min.   : 26.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 98.0   1st Qu.:211   1st Qu.:110.0   1st Qu.:  0.000   1st Qu.:0  
 Median :133.0   Median :232   Median :132.0   Median :  0.000   Median :0  
 Mean   :126.1   Mean   :232   Mean   :132.8   Mean   :  3.354   Mean   :0  
 3rd Qu.:160.0   3rd Qu.:254   3rd Qu.:156.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :231.0   Max.   :349   Max.   :228.0   Max.   :106.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:36.85   1st Qu.: -6.2567   1st Qu.:  27.0  
 Median :   0.0000   Median :40.66   Median : -2.9056   Median :  72.0  
 Mean   :   0.0235   Mean   :38.52   Mean   : -4.0086   Mean   : 269.5  
 3rd Qu.:   0.0000   3rd Qu.:41.83   3rd Qu.:  0.8031   3rd Qu.: 427.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBkaWEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiA3MwoqIERlc2NyaXBjacOzbjogCiogRnJlY3VlbmNpYTogZGlhCiogVmFyaWFibGVzOiBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcAoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiA1LDUKKiBJdGVyYWNpb25lczogMTAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTA3My5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19kaWFfMmsuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDUqNTsKbGVuX25iID0gbGVuZ3RoKG5iKTsKZW1wdHlfbm9kZXMgPC0gZGltX21vZGVsICE9IGxlbl9uYjsKaWYgKGVtcHR5X25vZGVzKSB7CiAgcHJpbnQocGFzdGUoIltXYXJuaW5nXSBFeGlzdGVuIG5vZG9zIHZhY8Otb3M6ICIsIGxlbl9uYiwgIi8iLCBkaW1fbW9kZWwpKQp9CmBgYAoKIyBNYXBhIGRlIGRpc3RhbmNpYSBlbnRyZSB2ZWNpbm9zCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iZGlzdC5uZWlnaGJvdXJzIiwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMgSW5mbHVlbmNpYSBkZSBsYXMgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfY29sbmFtZXMgPSBjKCJmZWNoYV9jbnQiLCAidG1heCIsICJ0bWluIiwgInByZWNpcCIpCm1vZGVsX25jb2wgPSBsZW5ndGgobW9kZWxfY29sbmFtZXMpCmBgYAoKIyMgTWFwYSBkZSB2YXJpYWJsZXMuCgpgYGB7cn0KcGxvdChtb2RlbCwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMjIE1hcGEgZGUgY2Fsb3IgcG9yIHZhcmlhYmxlCgpgYGB7cn0KcGFyKG1mcm93PWMoMyw0KSkKZm9yIChqIGluIDE6bW9kZWxfbmNvbCkgewogIHBsb3QobW9kZWwsIHR5cGU9InByb3BlcnR5IiwgcHJvcGVydHk9Z2V0Q29kZXMobW9kZWwsMSlbLGpdLAogICAgcGFsZXR0ZS5uYW1lPW1wci5jb29sQmx1ZUhvdFJlZCwKICAgIG1haW49bW9kZWxfY29sbmFtZXNbal0sCiAgICBjZXg9MC41LCBzaGFwZSA9ICJzdHJhaWdodCIpCn0KYGBgCgojIyBDb3JyZWxhY2nDs24gcGFyYSBjYWRhIGNvbHVtbmEgZGVsIHZlY3RvciBkZSBub2RvcwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBjb3IgPC0gYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksIDIsIG1wci53ZWlnaHRlZC5jb3JyZWxhdGlvbiwgdz1uYiwgc29tPW1vZGVsKQogIHByaW50KGNvcikKfQpgYGAKClJlcHJlc2VudGFjacOzbiBkZSBjYWRhIHZhcmlhYmxlIGVuIHVuIG1hcGEgZGUgZmFjdG9yZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBhcihtZnJvdz1jKDEsMSkpCiAgcGxvdChjb3JbMSxdLCBjb3JbMixdLCB4bGltPWMoLTEsMSksIHlsaW09YygtMSwxKSwgdHlwZT0ibiIpCiAgbGluZXMoYygtMSwxKSxjKDAsMCkpCiAgbGluZXMoYygwLDApLGMoLTEsMSkpCiAgdGV4dChjb3JbMSxdLCBjb3JbMixdLCBsYWJlbHM9bW9kZWxfY29sbmFtZXMsIGNleD0wLjc1KQogIHN5bWJvbHMoMCwwLGNpcmNsZXM9MSxpbmNoZXM9RixhZGQ9VCkKfQpgYGAKCkltcG9ydGFuY2lhIGRlIGNhZGEgdmFyaWFibGUgLSB2YXJpYW56YSBwb25kZXJhZGEgcG9yIGVsIHRhbWHDsW8gZGUgbGEgY2VsZGE6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHNpZ21hMiA8LSBzcXJ0KGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLDIsZnVuY3Rpb24oeCxlZmZlY3RpZikKICAgICB7bTwtc3VtKGVmZmVjdGlmKih4LXdlaWdodGVkLm1lYW4oeCxlZmZlY3RpZikpXjIpLyhzdW0oZWZmZWN0aWYpLTEpfSwKICAgICBlZmZlY3RpZj1uYikpCiAgcHJpbnQoc29ydChzaWdtYTIsZGVjcmVhc2luZz1UKSkKfQpgYGAKCiMgQ2x1c3RlcmluZwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBoYWMgPC0gbXByLmhhYyhtb2RlbCwgbmIpCn0KYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAzIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MykKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTMpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTQpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz00KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA1IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NSkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTUpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA2IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NikKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTYpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgOCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTgpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz04KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMTAgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0xMCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTEwKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQogIGRmLmNsdXN0ZXIwOSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTkpCiAgZGYuY2x1c3RlcjEwIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MTApCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDkgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjEwIDwtIHNlbGVjdChkZi5jbHVzdGVyMTAsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0sIGRpbShkZi5jbHVzdGVyMDkpWzFdLCBkaW0oZGYuY2x1c3RlcjEwKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiLCAiY2x1c3RlcjA5IiwgImNsdXN0ZXIxMCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMTApCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMTApCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQogIGRmLmNsdXN0ZXIwOS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA5KQogIGRmLmNsdXN0ZXIxMC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjEwKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA5Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjEwLmdyb3VwZWQpCmBgYAo=